package ch.uzh.ifi.sonar.shells;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import org.eclipse.swt.SWT;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.DateTime;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.List;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.Widget;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.console.MessageConsole;

import ch.uzh.ifi.sonar.analyzers.CRAnalyzer;
import ch.uzh.ifi.sonar.analyzers.StreamAnalyzer;
import ch.uzh.ifi.sonar.importers.ClearCaseImporter;
import ch.uzh.ifi.sonar.storage.IStorage;
import ch.uzh.ifi.sonar.storage.StorageResult;
import ch.uzh.ifi.sonar.storage.TeneoHibernateStorage;
import ch.uzh.ifi.sonar.util.SonarConstant;
import ch.uzh.ifi.sonar.util.SonarUtility;

public class QueryTab extends Tab {
	
	public static final String[] HEADER = new String[] { "Ticket", "close",
			"No. of changes", "STTLN", "STVAR", "STOPT", "STCCB" };

	private List streamList;
	private List selectedList;
	private IWorkbenchWindow window;
	public static Map<String, String> streamSrcMap;
	private MessageConsole console;

	private Combo ticketNumbers;
	private Combo streamCombo;
	private Text resultText;
	private Text timeSlotResultText;
	private Table ticketResultTable;

	private IStorage storage;

	DateTime startDate;
	DateTime endDate;

	private Group streamGroup;
	private Group timeSlotGroup;
	private Group ticketGroup;
	private Group consoleGroup;

	private Button streamsLaunchButton;
	private Button streamCMAButton;

	private Button ticketLaunchButton;
	private Button timeSlotLaunchButton;
	private Button detailSumSelected;
	

	private final ClearCaseImporter importer;

	/* Event logging variables and controls */
	Text eventConsole;
	boolean logging = false;

	QueryTab(SonarDashboard instance) {
		super(instance);
		storage = new TeneoHibernateStorage();

		streamSrcMap = new HashMap<String, String>();
		java.util.List<java.util.List<String>> streams = SonarUtility
				.readStreamContent();
		String labelStreamName;
		for (java.util.List<String> line : streams) {
			labelStreamName = line.get(0) + "(" + line.get(1) + ")["
					+ line.get(2) + "]"; // e.g.
											// prjIter_2700_Integration(X://CCFS/src)[2004]
			streamSrcMap.put(labelStreamName, line.get(1));
		}

		this.importer = new ClearCaseImporter();
	}

	@Override
	Widget[] getExampleWidgets() {

		return null;
	}

	@Override
	void createMainGroup() {

		mainGroup = new Group(tabFolderPage, SWT.NONE);
		mainGroup.setLayout(new GridLayout(2, true));
		GridData gd = new GridData(SWT.FILL, SWT.FILL, true, true);
		mainGroup.setLayoutData(gd);
		mainGroup.setText("Main Board");

		streamGroup = new Group(mainGroup, SWT.NONE);
		streamGroup.setLayout(new GridLayout(3, false));
		gd = new GridData(SWT.FILL, SWT.FILL, true, true);
		streamGroup.setLayoutData(gd);
		streamGroup.setText("Query by stream");
		fillStreamContent();

		ticketGroup = new Group(mainGroup, SWT.NONE);
		ticketGroup.setLayout(new GridLayout(3, false));
		gd = new GridData(SWT.FILL, SWT.FILL, true, false);
		ticketGroup.setLayoutData(gd);
		ticketGroup.setText("Query by CR ticket number");
		fillTicketContent();

		timeSlotGroup = new Group(mainGroup, SWT.NONE);
		timeSlotGroup.setLayout(new GridLayout(5, false));
		gd = new GridData(SWT.FILL, SWT.FILL, true, true);
		timeSlotGroup.setLayoutData(gd);
		timeSlotGroup.setText("Query by Selected Time Slot");
		fillTimeslotContent();

		consoleGroup = new Group(mainGroup, SWT.NONE);
		consoleGroup.setLayout(new GridLayout(3, false));
		consoleGroup
				.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
		consoleGroup.setText("Log Panel");
		/*
		 * Create the button to clear the text.
		 */
		Button clearButton = new Button(consoleGroup, SWT.PUSH);
		clearButton.setText("Clear");
		clearButton.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_END));
		clearButton.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent e) {
				eventConsole.setText("");
			}
		});
		eventConsole = new Text(consoleGroup, SWT.BORDER | SWT.MULTI
				| SWT.V_SCROLL | SWT.H_SCROLL);
		gd = new GridData(GridData.FILL_BOTH);
		gd.horizontalSpan = 3;
		gd.heightHint = 80;
		eventConsole.setLayoutData(gd);

	}

	private void fillStreamContent() {
		streamList = new List(streamGroup, SWT.MULTI | SWT.BORDER
				| SWT.V_SCROLL | SWT.H_SCROLL);
		Set<String> allStream = streamSrcMap.keySet();
		java.util.List<String> sortedStream = new ArrayList<String>(allStream);
		Collections.sort(sortedStream);
		for (String item : sortedStream)
			streamList.add(item);
		GridData gd = new GridData(GridData.BEGINNING, GridData.BEGINNING,
				true, true);
		gd.minimumWidth = 180;
		gd.verticalSpan = 3;
		int listHeight = streamList.getItemHeight() * 12;
		Rectangle trim = streamList.computeTrim(0, 0, 0, listHeight);
		gd.heightHint = trim.height;
		streamList.setLayoutData(gd);
		Composite buttonGroup = new Composite(streamGroup, SWT.NONE);
		GridLayout gl = new GridLayout(1, true);
		// gl.marginWidth = gl.marginHeight = 0;
		// gl.numColumns = 1;
		buttonGroup.setLayout(gl);
		buttonGroup.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, false,
				true));
		gd = new GridData(GridData.CENTER, GridData.CENTER, true, true);
		buttonGroup.setLayoutData(gd);

		Button addButton = new Button(buttonGroup, SWT.PUSH);
		addButton.setText(">>");
		Button removeButton = new Button(buttonGroup, SWT.PUSH);
		removeButton.setText("<<");
		gd = new GridData(GridData.BEGINNING,
				GridData.HORIZONTAL_ALIGN_BEGINNING, false, false);
		gd.verticalSpan = 3;
		buttonGroup.setLayoutData(gd);

		Composite rightGroup = new Composite(streamGroup, SWT.NONE);
		rightGroup.setLayout(new GridLayout(2, true));
		rightGroup.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
		selectedList = new List(rightGroup, SWT.MULTI | SWT.BORDER
				| SWT.V_SCROLL);
		gd = new GridData(SWT.FILL, SWT.BEGINNING, true, false, 2, 1);
		listHeight = selectedList.getItemHeight() * 12;
		trim = selectedList.computeTrim(0, 0, 0, listHeight);
		gd.heightHint = trim.height;
		gd.verticalSpan = 3;
		// selectedList.add("XXXXXXXXXXXXXXXXXXXXXXX");
		selectedList.setLayoutData(gd);
		streamsLaunchButton = new Button(rightGroup, SWT.PUSH);
		streamsLaunchButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL,
				true, true));
		streamsLaunchButton.setText("launch");
		streamsLaunchButton
				.addSelectionListener(new LaunchStreamAnalysisHandler());

		Button cancelButton = new Button(rightGroup, SWT.PUSH);
		cancelButton
				.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
		cancelButton.setText("cancel");

		cancelButton.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				/* TODO: stop the stream analysis process */
			}

		});
		detailSumSelected = new Button(streamGroup, SWT.CHECK);
		detailSumSelected.setText("generate detailed summary file? ");
		detailSumSelected.setSelection(true);
		detailSumSelected.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false,
				false));
		detailSumSelected.addSelectionListener(new SelectionAdapter() {

			@Override
			public void widgetSelected(SelectionEvent e) {
				/* TODO: select the change selection */
				SonarUtility.Alert("selected? ",
						"detailSumSelected changed selection");
			}

		});

		Button generateSumButton = new Button(streamGroup, SWT.PUSH);
		generateSumButton.setText("Generate Summary CSV File");
		generateSumButton.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false,
				false));
		generateSumButton.addSelectionListener(new GenerateSumHandler());

		addButton.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent event) {
				addStreams();
			}
		});

		removeButton.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent event) {
				removeStreams();
			}
		});

		streamList.addMouseListener(new MouseAdapter() {
			@Override
			public void mouseDoubleClick(MouseEvent e) {
				addStreams();
			}
		});

		selectedList.addMouseListener(new MouseAdapter() {
			@Override
			public void mouseDoubleClick(MouseEvent e) {
				removeStreams();
			}
		});
	}

	private void addStreams() {
		java.util.List<String> existingItems = Arrays.asList(selectedList
				.getItems());
		java.util.List<String> selectedItems = Arrays.asList(streamList
				.getSelection());
		for (String item : selectedItems) {
			if (!existingItems.contains(item)) {
				selectedList.add(item);
			}
		}
	}

	private void removeStreams() {
		java.util.List<String> items = Arrays.asList(selectedList.getItems());
		java.util.List<String> selectedItems = Arrays.asList(selectedList
				.getSelection());
		for (String item : items) {
			if (selectedItems.contains(item)) {
				selectedList.remove(item);
			}
		}
	}

	private void fillTicketContent() {
		new Label(ticketGroup, SWT.NONE).setText("Select a stream: ");
		streamCombo = new Combo(ticketGroup, SWT.NONE);
		GridData gd = new GridData(GridData.FILL, GridData.CENTER, true, false);
		gd.horizontalSpan = 2;
		streamCombo.setLayoutData(gd);
		java.util.List<String> streams = importer.getStreamsFromCSV();
		this.setComboContent(streamCombo, streams);
		streamCombo.select(streams.size() - 1);
		System.out.println("[init: ]" + streamCombo.getText());
		new Label(ticketGroup, SWT.NONE).setText("Ticket Number: ");
		ticketNumbers = new Combo(ticketGroup, SWT.NONE);
		gd = new GridData(GridData.FILL, GridData.CENTER, true, false);
		gd.horizontalSpan = 2;
		ticketNumbers.setLayoutData(gd);

		this.setComboContent(streamCombo, streams);
		streamCombo.addSelectionListener(new ComboSelectionHandler(streamCombo,
				ticketNumbers) {
			@Override
			public java.util.List<String> getCombo2List(Combo combo1) {
				return importer.getStreamUCM(combo1.getText());
			}

			@Override
			public void widgetSelected(SelectionEvent e) {
				super.widgetSelected(e);
				log("Selection:" + streamCombo.getText());
			}
		});

		// String selectedStream = streamCombo.getText();
		/*
		 * java.util.List<String> ucms = importer.getAllIntegrationUCM();
		 * 
		 * 
		 * for(String ucm: ucms) ticketNumbers.add(ucm);
		 */
		// TODO add result
		resultText = new Text(ticketGroup, SWT.BORDER | SWT.H_SCROLL
				| SWT.V_SCROLL | SWT.MULTI);

		gd = new GridData(SWT.FILL, SWT.FILL, true, true);
		gd.horizontalSpan = 3;
		gd.verticalSpan = 10;
		gd.grabExcessHorizontalSpace = true;
		gd.grabExcessVerticalSpace = true;
		gd.heightHint = 80;
		resultText.setLayoutData(gd);

		Button launchButton = new Button(ticketGroup, SWT.PUSH);
		gd = new GridData(GridData.HORIZONTAL_ALIGN_END,
				GridData.VERTICAL_ALIGN_CENTER, true, false);
		gd.horizontalSpan = 3;
		launchButton.setLayoutData(gd);
		launchButton.setText("Launch Analysis");
		launchButton.addSelectionListener(new LaunchTicketAnalysisHandler());

	}

	private void fillTimeslotContent() {
		/* 1st column */
		new Label(timeSlotGroup, SWT.NONE).setText("Start date: ");
		/* 2nd column */
		startDate = new DateTime(timeSlotGroup, SWT.BORDER | SWT.DATE
				| SWT.DROP_DOWN);
		GridData gd = new GridData(GridData.FILL, GridData.CENTER, true, false);
		startDate.setLayoutData(gd);
		/* 3rd column */
		new Label(timeSlotGroup, SWT.NONE).setText("End date: ");
		/* 4th column */
		endDate = new DateTime(timeSlotGroup, SWT.BORDER | SWT.DATE
				| SWT.DROP_DOWN);
		gd = new GridData(GridData.FILL, GridData.CENTER, true, false);
		endDate.setLayoutData(gd);

		/* 5th column */
		Button launchButton = new Button(timeSlotGroup, SWT.PUSH);
		gd = new GridData(GridData.HORIZONTAL_ALIGN_END,
				GridData.VERTICAL_ALIGN_CENTER, true, false);
		launchButton.setLayoutData(gd);
		launchButton.setText("start");
		launchButton.addSelectionListener(new LaunchTimeSlotAnalysisHandler());

		ticketResultTable = new Table(timeSlotGroup, SWT.MULTI | SWT.BORDER
				| SWT.FULL_SELECTION);
		gd = new GridData(SWT.FILL, SWT.FILL, true, true);
		gd.horizontalSpan = 5;
		gd.verticalSpan = 10;
		gd.heightHint = 120;
		ticketResultTable.setLayoutData(gd);
		ticketResultTable.setLinesVisible(true);
		ticketResultTable.setHeaderVisible(true);

		
		for (int i = 0; i < HEADER.length; i++) {
			TableColumn column = new TableColumn(ticketResultTable, SWT.NONE);
			column.setText(HEADER[i]);
			ticketResultTable.getColumn(i).pack();
		}

		/*
		 * timeSlotResultText = new Text(timeSlotGroup, SWT.BORDER |
		 * SWT.H_SCROLL | SWT.V_SCROLL | SWT.MULTI); gd = new GridData(SWT.FILL,
		 * SWT.FILL, true, true); gd.horizontalSpan = 4; gd.verticalSpan = 10;
		 * gd.grabExcessHorizontalSpace = true; gd.grabExcessVerticalSpace =
		 * true; gd.heightHint = 120; timeSlotResultText.setLayoutData(gd);
		 */

	}

	/**
	 * Logs a string to the event console.
	 */
	void log(String string) {
		if (!eventConsole.isDisposed()) {
			eventConsole.append(string);
			eventConsole.append("\n");
		}
	}

	@Override
	String getTabText() {
		// TODO Auto-generated method stub
		return "Query";
	}

	private class LaunchTimeSlotAnalysisHandler extends SelectionAdapter {

		private void fillResultTable(java.util.List<?> ticketList) {
			CRAnalyzer ca;
			boolean grayed = false;
			for (Object o : ticketList) {
				log((String) o);
				ca = new CRAnalyzer((String) o);
				if (ca.getCRDate() != null) {
					TableItem item = ca.getTicketMetricItem(ticketResultTable,
							SWT.NONE);
					item.setGrayed(grayed);
					grayed = !grayed;
				}
			}
			for (int i = 0; i < ticketResultTable.getColumns().length; i++) {
				ticketResultTable.getColumns()[i].pack();
			}
		}

		private void fillCSVFile(java.util.List<?> ticketList)
				throws ParseException, IOException {
			SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
			String CSV_SEP = SonarConstant.CSV_SEP;
			Date start = format.parse(Integer.toString(startDate.getYear())
					+ "-" + Integer.toString(startDate.getMonth() + 1) + "-"
					+ Integer.toString(startDate.getDay()));
			String startString = format.format(start);
			Date end = format.parse(Integer.toString(endDate.getYear()) + "-"
					+ Integer.toString(endDate.getMonth() + 1) + "-"
					+ Integer.toString(endDate.getDay()));
			String endString = format.format(end);

			String sumPath = SonarUtility.getAbsolutePath(SonarUtility
					.getSettingString("SSQA_RESULT_PATH"));
			FileWriter writer = new FileWriter(sumPath + File.separatorChar
					+ startString + "_to_" + endString + ".csv");
			// summary header
			writer.append("Ticket Name ");
			writer.append(CSV_SEP);
			writer.append("ticket close date");
			writer.append(CSV_SEP);
			writer.append("Source File No.");
			writer.append(CSV_SEP);
			writer.append("STVAR");
			writer.append(CSV_SEP);
			writer.append("STOPT");
			writer.append(CSV_SEP);
			writer.append("STCCB");
			writer.append(CSV_SEP);
			writer.append("STTLN");
			writer.append(System.getProperty("line.separator"));
			CRAnalyzer ca = null;
			for (Object o : ticketList) {
				log((String) o);
				ca = new CRAnalyzer((String) o);
				if (ca.getCRDate() != null) {
					String caStr = ca.csvLine();
					timeSlotResultText.append("\n" + caStr);
					log(caStr);
					writer.append(caStr);

				}
			}
			writer.flush();
			writer.close();

		}

		@Override
		public void widgetSelected(SelectionEvent e) {

			// MessageConsoleStream consoleStream = console.newMessageStream();
			log("### time slot query launched ###");

			SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
			try {
				String CSV_SEP = SonarConstant.CSV_SEP;
				Date start = format.parse(Integer.toString(startDate.getYear())
						+ "-" + Integer.toString(startDate.getMonth() + 1)
						+ "-" + Integer.toString(startDate.getDay()));
				String startString = format.format(start);
				Date end = format.parse(Integer.toString(endDate.getYear())
						+ "-" + Integer.toString(endDate.getMonth() + 1) + "-"
						+ Integer.toString(endDate.getDay()));
				String endString = format.format(end);
				log("start: " + format.format(start) + "\n end: "
						+ format.format(end));

				String queryString = "SELECT i.id FROM sonar1.issue i"
						+ " INNER JOIN sonar1.timetracking t ON t.e_id = i.timetracking_timetracking_e_id "
						+ " WHERE t.enddate > '" + startString
						+ "' AND t.enddate < '" + endString
						+ "' order by t.enddate";

				StorageResult rs = storage.executeListSQLQuery(queryString);
				java.util.List<?> ticketList = rs.getListResult();
				if(ticketList.size() > 0){
					fillResultTable(ticketList);
					fillCSVFile(ticketList);					
				}
/*				CRAnalyzer ca = null;
				String sumPath;
				if (ticketList.size() > 0) {
					fillResultTable(ticketList);

					sumPath = SonarUtility.getAbsolutePath(SonarUtility
							.getSettingString("SSQA_RESULT_PATH"));
					FileWriter writer = new FileWriter(sumPath
							+ File.separatorChar + startString + "_to_"
							+ endString + ".csv");
					// summary header
					writer.append("Ticket Name ");
					writer.append(CSV_SEP);
					writer.append("ticket close date");
					writer.append(CSV_SEP);
					writer.append("Source File No.");
					writer.append(CSV_SEP);
					writer.append("STVAR");
					writer.append(CSV_SEP);
					writer.append("STOPT");
					writer.append(CSV_SEP);
					writer.append("STCCB");
					writer.append(CSV_SEP);
					writer.append("STTLN");
					writer.append(System.getProperty("line.separator"));
					for (Object o : ticketList) {
						log((String) o);
						ca = new CRAnalyzer((String) o);
						if (ca.getCRDate() != null) {
							String caStr = ca.csvLine();
							timeSlotResultText.append("\n" + caStr);
							log(caStr);
							writer.append(caStr);

						}
					}
					writer.flush();
					writer.close();
				}*/

			} catch (ParseException e1) {
				e1.printStackTrace();
			} catch (IOException e1) {
				e1.printStackTrace();
			}
		}

	}

	private class LaunchTicketAnalysisHandler extends SelectionAdapter {

		@Override
		public void widgetSelected(SelectionEvent e) {
			CRAnalyzer cra = new CRAnalyzer(ticketNumbers.getText());
			String resultString = cra.crResultToString();
			log(resultString);

		}
	}

	private class LaunchStreamAnalysisHandler extends SelectionAdapter {

		@Override
		public void widgetSelected(SelectionEvent e) {
			super.widgetSelected(e);
			String[] items = selectedList.getItems();

			/* FIXME TODO: GUI threading! */
			for (String stream : items) {
				log("start analyzing: " + stream);
				StreamAnalyzer analyzer = new StreamAnalyzer(stream,
						streamSrcMap.get(stream), eventConsole);
				try {
					analyzer.analyze(stream);
				} catch (IOException e1) {
					e1.printStackTrace();
				}
			}

		}
	}

	// private class AddStreamsToListHandler extends

	private class GenerateSumHandler extends SelectionAdapter {
		@Override
		public void widgetSelected(SelectionEvent e) {
			/*
			 * TODO: refactor to not use null as StreamAnalyzer constructor
			 * parameters
			 */
			StreamAnalyzer analyzer = new StreamAnalyzer(null, null,
					eventConsole);
			analyzer.persistSummary();
		}

	}

	private void setComboContent(Combo combo, java.util.List<String> list) {
		if (combo != null) {
			combo.removeAll();
			for (String str : list) {
				combo.add(str);
			}
		}
	}

	/*
	 * the first combo was selected and the second combo update based on the
	 * value of the first combo
	 */
	private abstract class ComboSelectionHandler extends SelectionAdapter {
		private final Combo combo1;
		private final Combo combo2;

		public ComboSelectionHandler(final Combo combo1, final Combo combo2) {
			this.combo1 = combo1;
			this.combo2 = combo2;
		}

		@Override
		public void widgetSelected(SelectionEvent e) {
			if (combo1 != null && combo2 != null) {
				java.util.List<String> caculatedList = getCombo2List(combo1);
				setComboContent(combo2, caculatedList);
			}
		}

		public abstract java.util.List<String> getCombo2List(Combo combo1);

		private void setComboContent(Combo combo, java.util.List<String> list) {
			if (combo != null) {
				combo.removeAll();
				for (String str : list) {
					combo.add(str);
				}
			}
		}

	}
}
